{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook is an interactive version of the [companion webpage](http://edwardlib.org/iclr2017) for the article, Deep Probabilistic Programming [(Tran et al., 2017)](https://arxiv.org/abs/1701.03757). See Edward's [API](http://edwardlib.org/api/) for details on how to interact with data, models, inference, and criticism.\n",
    "\n",
    "The code snippets assume the following versions.\n",
    "```bash\n",
    "pip install edward==1.3.1\n",
    "pip install tensorflow==1.1.0  # alternatively, tensorflow-gpu==1.1.0\n",
    "pip install keras==2.0.0\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Section 3. Compositional Representations for Probabilistic Models\n",
    "\n",
    "__Figure 1__. Beta-Bernoulli program."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Bernoulli, Beta\n",
    "\n",
    "theta = Beta(1.0, 1.0)\n",
    "x = Bernoulli(tf.ones(50) * theta)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an example of it in use, see\n",
    "[`examples/beta_bernoulli.py`](https://github.com/blei-lab/edward/blob/master/examples/beta_bernoulli.py)\n",
    "in the Github repository.\n",
    "\n",
    "__Figure 2__. Variational auto-encoder for a data set of 28 x 28 pixel images\n",
    "(Kingma & Welling, 2014; Rezende, Mohamed, & Wierstra, 2014)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Bernoulli, Normal\n",
    "from keras.layers import Dense\n",
    "\n",
    "N = 55000  # number of data points\n",
    "d = 50  # latent dimension\n",
    "\n",
    "# Probabilistic model\n",
    "z = Normal(loc=tf.zeros([N, d]), scale=tf.ones([N, d]))\n",
    "h = Dense(256, activation='relu')(z)\n",
    "x = Bernoulli(logits=Dense(28 * 28, activation=None)(h))\n",
    "\n",
    "# Variational model\n",
    "qx = tf.placeholder(tf.float32, [N, 28 * 28])\n",
    "qh = Dense(256, activation='relu')(qx)\n",
    "qz = Normal(loc=Dense(d, activation=None)(qh),\n",
    "            scale=Dense(d, activation='softplus')(qh))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an example of it in use, see\n",
    "[`examples/vae.py`](https://github.com/blei-lab/edward/blob/master/examples/vae.py)\n",
    "in the Github repository.\n",
    "\n",
    "__Figure 3__. Bayesian recurrent neural network (Radford M Neal, 2012).\n",
    "The program has an unspecified number of time steps; it uses a\n",
    "symbolic for loop (`tf.scan`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import tensorflow as tf\n",
    "from edward.models import Normal\n",
    "\n",
    "H = 50  # number of hidden units\n",
    "D = 10  # number of features\n",
    "\n",
    "def rnn_cell(hprev, xt):\n",
    "  return tf.tanh(ed.dot(hprev, Wh) + ed.dot(xt, Wx) + bh)\n",
    "\n",
    "Wh = Normal(loc=tf.zeros([H, H]), scale=tf.ones([H, H]))\n",
    "Wx = Normal(loc=tf.zeros([D, H]), scale=tf.ones([D, H]))\n",
    "Wy = Normal(loc=tf.zeros([H, 1]), scale=tf.ones([H, 1]))\n",
    "bh = Normal(loc=tf.zeros(H), scale=tf.ones(H))\n",
    "by = Normal(loc=tf.zeros(1), scale=tf.ones(1))\n",
    "\n",
    "x = tf.placeholder(tf.float32, [None, D])\n",
    "h = tf.scan(rnn_cell, x, initializer=tf.zeros(H))\n",
    "y = Normal(loc=tf.matmul(h, Wy) + by, scale=1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Section 4. Compositional Representations for Inference\n",
    "\n",
    "__Figure 5__. Hierarchical model (Gelman & Hill, 2006).\n",
    "  It is a mixture of Gaussians over\n",
    "  $D$-dimensional data $\\{x_n\\}\\in\\mathbb{R}^{N\\times D}$. There are\n",
    "  $K$ latent cluster means $\\beta\\in\\mathbb{R}^{K\\times D}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Categorical, Normal\n",
    "\n",
    "N = 10000  # number of data points\n",
    "D = 2  # data dimension\n",
    "K = 5  # number of clusters\n",
    "\n",
    "beta = Normal(loc=tf.zeros([K, D]), scale=tf.ones([K, D]))\n",
    "z = Categorical(logits=tf.zeros([N, K]))\n",
    "x = Normal(loc=tf.gather(beta, z), scale=tf.ones([N, D]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is used below in Figure 6 (left/right) and Figure * (variational EM).\n",
    "\n",
    "__Figure 6__ __(left)__. Variational inference\n",
    "(Jordan, Ghahramani, Jaakkola, & Saul, 1999).\n",
    "It performs inference on the model defined in Figure 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from edward.models import Categorical, Normal\n",
    "\n",
    "x_train = np.zeros([N, D])\n",
    "\n",
    "qbeta = Normal(loc=tf.Variable(tf.zeros([K, D])),\n",
    "               scale=tf.exp(tf.Variable(tf.zeros([K, D]))))\n",
    "qz = Categorical(logits=tf.Variable(tf.zeros([N, K])))\n",
    "\n",
    "inference = ed.VariationalInference({beta: qbeta, z: qz}, data={x: x_train})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Figure 6__ __(right)__. Monte Carlo (Robert & Casella, 1999).\n",
    "It performs inference on the model defined in Figure 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from edward.models import Empirical\n",
    "\n",
    "x_train = np.zeros([N, D])\n",
    "\n",
    "T = 10000  # number of samples\n",
    "qbeta = Empirical(params=tf.Variable(tf.zeros([T, K, D])))\n",
    "qz = Empirical(params=tf.Variable(tf.zeros([T, N])))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Figure 7__. Generative adversarial network\n",
    "(Goodfellow et al., 2014)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from edward.models import Normal\n",
    "from keras.layers import Dense\n",
    "\n",
    "N = 55000  # number of data points\n",
    "d = 50  # latent dimension\n",
    "\n",
    "def generative_network(eps):\n",
    "  h = Dense(256, activation='relu')(eps)\n",
    "  return Dense(28 * 28, activation=None)(h)\n",
    "\n",
    "def discriminative_network(x):\n",
    "  h = Dense(28 * 28, activation='relu')(x)\n",
    "  return Dense(1, activation=None)(h)\n",
    "\n",
    "# DATA\n",
    "x_train = np.zeros([N, 28 * 28])\n",
    "\n",
    "# MODEL\n",
    "eps = Normal(loc=tf.zeros([N, d]), scale=tf.ones([N, d]))\n",
    "x = generative_network(eps)\n",
    "\n",
    "# INFERENCE\n",
    "inference = ed.GANInference(data={x: x_train},\n",
    "                            discriminator=discriminative_network)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an example of it in use, see the\n",
    "[generative adversarial networks](http://edwardlib.org/tutorials/gan) tutorial.\n",
    "\n",
    "__Figure *__. Variational EM (Radford M. Neal & Hinton, 1993).\n",
    "It performs inference on the model defined in Figure 5."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from edward.models import Categorical, PointMass\n",
    "\n",
    "# DATA\n",
    "x_train = np.zeros([N, D])\n",
    "\n",
    "# INFERENCE\n",
    "qbeta = PointMass(params=tf.Variable(tf.zeros([K, D])))\n",
    "qz = Categorical(logits=tf.Variable(tf.zeros([N, K])))\n",
    "\n",
    "inference_e = ed.VariationalInference({z: qz}, data={x: x_train, beta: qbeta})\n",
    "inference_m = ed.MAP({beta: qbeta}, data={x: x_train, z: qz})\n",
    "\n",
    "inference_e.initialize()\n",
    "inference_m.initialize()\n",
    "\n",
    "tf.initialize_all_variables().run()\n",
    "\n",
    "for _ in range(10000):\n",
    "  inference_e.update()\n",
    "  inference_m.update()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more details, see the\n",
    "[inference compositionality](http://edwardlib.org/api/inference-compositionality) webpage.\n",
    "See\n",
    "[`examples/factor_analysis.py`](https://github.com/blei-lab/edward/blob/master/examples/factor_analysis.py) for\n",
    "a version performing Monte Carlo EM for logistic factor analysis\n",
    "in the Github repository.\n",
    "It leverages Hamiltonian Monte Carlo for the E-step to perform maximum\n",
    "marginal a posteriori.\n",
    "\n",
    "__Figure *__. Data subsampling."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import tensorflow as tf\n",
    "from edward.models import Categorical, Normal\n",
    "\n",
    "N = 10000  # number of data points\n",
    "M = 128  # batch size during training\n",
    "D = 2  # data dimension\n",
    "K = 5  # number of clusters\n",
    "\n",
    "# DATA\n",
    "x_batch = tf.placeholder(tf.float32, [M, D])\n",
    "\n",
    "# MODEL\n",
    "beta = Normal(loc=tf.zeros([K, D]), scale=tf.ones([K, D]))\n",
    "z = Categorical(logits=tf.zeros([M, K]))\n",
    "x = Normal(loc=tf.gather(beta, z), scale=tf.ones([M, D]))\n",
    "\n",
    "# INFERENCE\n",
    "qbeta = Normal(loc=tf.Variable(tf.zeros([K, D])),\n",
    "               scale=tf.nn.softplus(tf.Variable(tf.zeros([K, D]))))\n",
    "qz = Categorical(logits=tf.Variable(tf.zeros([M, D])))\n",
    "\n",
    "inference = ed.VariationalInference({beta: qbeta, z: qz}, data={x: x_batch})\n",
    "inference.initialize(scale={x: float(N) / M, z: float(N) / M})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more details, see the\n",
    "[data subsampling](http://edwardlib.org/api/inference-data-subsampling) webpage.\n",
    "\n",
    "## Section 5. Experiments\n",
    "\n",
    "__Figure 9__. Bayesian logistic regression with Hamiltonian Monte Carlo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import edward as ed\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from edward.models import Bernoulli, Empirical, Normal\n",
    "\n",
    "N = 581012  # number of data points\n",
    "D = 54  # number of features\n",
    "T = 100  # number of empirical samples\n",
    "\n",
    "# DATA\n",
    "x_data = np.zeros([N, D])\n",
    "y_data = np.zeros([N])\n",
    "\n",
    "# MODEL\n",
    "x = tf.Variable(x_data, trainable=False)\n",
    "beta = Normal(loc=tf.zeros(D), scale=tf.ones(D))\n",
    "y = Bernoulli(logits=ed.dot(x, beta))\n",
    "\n",
    "# INFERENCE\n",
    "qbeta = Empirical(params=tf.Variable(tf.zeros([T, D])))\n",
    "inference = ed.HMC({beta: qbeta}, data={y: y_data})\n",
    "inference.run(step_size=0.5 / N, n_steps=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an example of it in use, see\n",
    "[`examples/bayesian_logistic_regression.py`](https://github.com/blei-lab/edward/blob/master/examples/bayesian_logistic_regression.py)\n",
    "in the Github repository.\n",
    "\n",
    "## Appendix A. Model Examples\n",
    "\n",
    "__Figure 10__. Bayesian neural network for classification (Denker, Schwartz, Wittner, & Solla, 1987)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Bernoulli, Normal\n",
    "\n",
    "N = 1000  # number of data points\n",
    "D = 528  # number of features\n",
    "H = 256  # hidden layer size\n",
    "\n",
    "W_0 = Normal(loc=tf.zeros([D, H]), scale=tf.ones([D, H]))\n",
    "W_1 = Normal(loc=tf.zeros([H, 1]), scale=tf.ones([H, 1]))\n",
    "b_0 = Normal(loc=tf.zeros(H), scale=tf.ones(H))\n",
    "b_1 = Normal(loc=tf.zeros(1), scale=tf.ones(1))\n",
    "\n",
    "x = tf.placeholder(tf.float32, [N, D])\n",
    "y = Bernoulli(logits=tf.matmul(tf.nn.tanh(tf.matmul(x, W_0) + b_0), W_1) + b_1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For an example of it in use, see\n",
    "[`examples/getting_started_example.py`](https://github.com/blei-lab/edward/blob/master/examples/getting_started_example.py)\n",
    "in the Github repository.\n",
    "\n",
    "__Figure 11__. Latent Dirichlet allocation (D. M. Blei, Ng, & Jordan, 2003)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Categorical, Dirichlet\n",
    "\n",
    "D = 4  # number of documents\n",
    "N = [11502, 213, 1523, 1351]  # words per doc\n",
    "K = 10  # number of topics\n",
    "V = 100000  # vocabulary size\n",
    "\n",
    "theta = Dirichlet(tf.zeros([D, K]) + 0.1)\n",
    "phi = Dirichlet(tf.zeros([K, V]) + 0.05)\n",
    "z = [[0] * N] * D\n",
    "w = [[0] * N] * D\n",
    "for d in range(D):\n",
    "  for n in range(N[d]):\n",
    "    z[d][n] = Categorical(theta[d, :])\n",
    "    w[d][n] = Categorical(phi[z[d][n], :])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Figure 12__. Gaussian matrix factorization\n",
    "(Salakhutdinov & Mnih, 2011)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import Normal\n",
    "\n",
    "N = 10\n",
    "M = 10\n",
    "K = 5  # latent dimension\n",
    "\n",
    "U = Normal(loc=tf.zeros([M, K]), scale=tf.ones([M, K]))\n",
    "V = Normal(loc=tf.zeros([N, K]), scale=tf.ones([N, K]))\n",
    "Y = Normal(loc=tf.matmul(U, V, transpose_b=True), scale=tf.ones([N, M]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Figure 13__. Dirichlet process mixture model (Antoniak, 1974)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from edward.models import DirichletProcess, Normal\n",
    "\n",
    "N = 1000  # number of data points\n",
    "D = 5  # data dimensionality\n",
    "\n",
    "dp = DirichletProcess(alpha=1.0, base=Normal(loc=tf.zeros(D), scale=tf.ones(D)))\n",
    "mu = dp.sample(N)\n",
    "x = Normal(loc=loc, scale=tf.ones([N, D]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To see the essential component defining the `DirichletProcess`, see\n",
    "[`examples/pp_dirichlet_process.py`](https://github.com/blei-lab/edward/blob/master/examples/pp_dirichlet_process.py)\n",
    "in the Github repository. Its source implementation can be found at\n",
    "[`edward/models/dirichlet_process.py`](https://github.com/blei-lab/edward/blob/master/edward/models/dirichlet_process.py).\n",
    "\n",
    "## Appendix B. Inference Examples\n",
    "\n",
    "__Figure *__. Stochastic variational inference (M. D. Hoffman, Blei, Wang, & Paisley, 2013). \n",
    "For more details, see the\n",
    "[data subsampling](http://edwardlib.org/api/inference-data-subsampling) webpage.\n",
    "\n",
    "## Appendix C. Complete Examples\n",
    "\n",
    "__Figure 15__. Variational auto-encoder\n",
    "(Kingma & Welling, 2014; Rezende et al., 2014).\n",
    "See the script\n",
    "\\href{https://github.com/blei-lab/edward/blob/master/examples/vae.py}{\\texttt{examples/vae.py}}\n",
    "in the Github repository.\n",
    "\n",
    "__Figure 16__. Exponential family embedding (Rudolph, Ruiz, Mandt, & Blei, 2016).\n",
    "A Github repository with comprehensive features is available at\n",
    "[mariru/exponential_family_embeddings](https://github.com/mariru/exponential_family_embeddings)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
